package cn.tedu.charging.cost.service.impl;

import cn.tedu.charging.common.pojo.param.ProgressCostParam;
import cn.tedu.charging.common.pojo.vo.ProgressCostVO;
import cn.tedu.charging.cost.dao.repository.CostRuleRepository;
import cn.tedu.charging.cost.pojo.po.ChargingCostRulePO;
import cn.tedu.charging.cost.service.CostService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;

@Service
@Slf4j
public class CostServiceImpl implements CostService {
    @Autowired
    private CostRuleRepository costRuleRepository;
    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public ProgressCostVO calculateCost(ProgressCostParam param) {
        //1.获取当前系统时间 小时数 10:58~10 12:03~12
        Integer hourNum=getCurrentHour();
        //2.根据当前条件stationId gunType hourNum
        ChargingCostRulePO costRule=getCostRule(param.getStationId(),1,hourNum);
        //3.利用已知条件计算单次度数
        BigDecimal onceCapacity=calculateOnceCapacity(param);
        //4.利用单价和单次度数计算总金额
        BigDecimal totalCost=calculateTotalCost(onceCapacity,costRule,param);
        //5.封装VO返回
        ProgressCostVO vo=new ProgressCostVO();
        vo.setTotalCost(totalCost.doubleValue());
        vo.setPowerFee(costRule.getPowerFee().doubleValue());
        vo.setChargingCapacity(onceCapacity.doubleValue());
        return vo;
    }

    private BigDecimal calculateTotalCost(BigDecimal onceCapacity, ChargingCostRulePO costRule, ProgressCostParam param) {
        //1.利用单次度数 和 单价 计算 本次金额
        BigDecimal currentCost = costRule.getPowerFee().multiply(onceCapacity);
        //2.利用redis 对绑定orderNo的key值做总金额的累加increment
        ValueOperations<String,Double> valueOps = redisTemplate.opsForValue();
        String totalCostKey="charging:order:total:"+param.getOrderNo();
        //3.调用increment
        Double totalCost = valueOps.increment(totalCostKey, currentCost.doubleValue());
        log.debug("订单的总金额:{}",totalCost);
        return new BigDecimal(totalCost);
    }

    private BigDecimal calculateOnceCapacity(ProgressCostParam param) {
        //获取操作redis 读写上次总度数的客户端string操作对象
        ValueOperations<String,Double> valueOps = redisTemplate.opsForValue();
        //1.准备一个key值,存储上次总度数,每张订单每次充电进度 都是同一个订单
        String orderLastCapacityKey="charging:order:laster:total:"+param.getOrderNo();
        //2.执行读取上次的总度数,将本次总度数写进key 在下一次用来当做上次总度数使用
        //set key currentTotalCapaicity GET
        Double lastTotal = valueOps.getAndSet(orderLastCapacityKey, param.getTotalCapacity());
        if (lastTotal==null){
            log.debug("第一次获取上次总度数,key:{}",orderLastCapacityKey);
            lastTotal=0.0;
        }
        //3.相减得到单次充电度数
        /*Double capacity=param.getTotalCapacity()-lastTotal;double直接减法 可能出现精度偏差*/
        BigDecimal onceCapacity=new BigDecimal(param.getTotalCapacity()).subtract(new BigDecimal(lastTotal));
        log.debug("单次充电度数:{}",onceCapacity);
        return onceCapacity;
    }

    private ChargingCostRulePO getCostRule(Integer stationId, Integer gunType, Integer hourNum) {
        log.debug("根据条件,stationId={},gunType={},hourNum={},获取满足条件的计价规则",stationId,gunType,hourNum);
        return costRuleRepository.getCostRule(stationId,hourNum);
    }

    private Integer getCurrentHour() {
        //1.方案1 localDateTime
        return LocalDateTime.now().getHour();
        //2.方案2 Calendar
        //return Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
        //3.方案3 Date
        //return new Date().getHours();
    }
}
